package com.base;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.apache.log4j.Logger;

import com.exception.DaoException;

/**
 * 数据库操作父类
 * @author acer
 *
 * @param <T>
 */
public class BaseDao<T> {

	private static final Logger logger = Logger.getLogger(BaseDao.class);

	protected Connection conn;
	protected PreparedStatement prep;
	protected ResultSet rs;

	private Class clazz;

	public BaseDao() {
		// 初始化
		// 获取T的真正类型

		// Class clazz = Class.forName("com.entity.Student");
		try {
			clazz = (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0];
		} catch (Exception e) {
			e.printStackTrace();
		}

	}

	public Connection getConnection() {

		return DbHelper.getConnection();
	}
	
	/**
	 * 查询总数
	 * @param sql
	 * @param objs
	 * @return
	 * @throws DaoException
	 */
	public int executeQueryCount(String sql, Object... objs) throws DaoException {
		try {
			
			//(SELECT)userid,username,..... (FROM news  where userid =? and ..... )(LIMIT ?,?)
			
			//正则
			sql = sql.replace("select", "SELECT");
			sql = sql.replace("SELECT", "SELECT");
			sql = sql.replace("from", "FROM");
			sql = sql.replace("FROM", "FROM");
			sql = sql.replace("limit", "LIMIT");
			sql = sql.replace("LIMIT", "LIMIT");
			sql = sql.replaceAll("(SELECT).*(FROM.*)(LIMIT.*)", "$1 COUNT(1) $2");
			conn = getConnection();
			prep = conn.prepareStatement(sql);

			for (int i = 0; i < objs.length; i++) {
				if(objs[i]!=null)
					prep.setObject(i + 1, objs[i]);
			}
			logger.info(prep.toString());

			rs = prep.executeQuery();

			if (rs.next()) {
				return rs.getInt(1);
			}else{
				return 0;
			}
		} catch (Exception e) {
			e.printStackTrace();
			throw new DaoException("执行查询失败!", e);
		} finally {
			close();
		}
	}

	/**
	 * 适用于查询
	 * 
	 * @param sql
	 * @param objs
	 * @return
	 * @throws DaoException
	 */
	public List<T> executeQuery(String sql, Object... objs) throws DaoException {
		try {
			conn = getConnection();
			prep = conn.prepareStatement(sql);

			for (int i = 0; i < objs.length; i++) {
				if(objs[i]!=null)
					prep.setObject(i + 1, objs[i]);
			}
			logger.info(prep.toString());

			rs = prep.executeQuery();
			// return rs;
			List<T> list = new ArrayList<T>();

			while (rs.next()) {

				// 创建对应查询的实体
				Object obj = clazz.newInstance();

				// Constructor constructor =
				// clazz.getConstructor(String.class,String.class);

				// 根据构造函数创建对象
				// Object obj2 =
				// constructor.newInstance(rs.getString("student_no"),rs.getString("student_name"));

				// 拿到实体类的字段
				Field[] fields = clazz.getDeclaredFields();
				for (Field field : fields) {
					String fieldName = field.getName();
					String conlumName = fieldName;// .replaceAll("([A-Z])",
													// "_$1").toLowerCase();//计算列名
					String methodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
					// 使用setXXX对属性赋值

					// 获取set方法
					Method method = clazz.getMethod(methodName, field.getType());

					// 赋值
					if (field.getType() == int.class) {
						method.invoke(obj, rs.getInt(conlumName));
					} else if (field.getType() == Date.class) {
						method.invoke(obj, rs.getDate(conlumName));
					} else {
						method.invoke(obj, rs.getString(conlumName));
					}
				}

				// Student student = new
				// Student(rs.getString("student_no"),rs.getString("student_name"));

				list.add((T)obj);
			}
			return list;
		} catch (Exception e) {
			e.printStackTrace();
			throw new DaoException("执行查询失败!", e);
		} finally {
			close();
		}
	}

	/**
	 * 适用于 增加 删除 修改
	 * 
	 * @param sql
	 * @param objs
	 * @return
	 * @throws DaoException
	 */
	public int executeUpdate(String sql, Object... objs) throws DaoException {
		try {
			conn = getConnection();
			prep = conn.prepareStatement(sql);

			for (int i = 0; i < objs.length; i++) {
				prep.setObject(i + 1, objs[i]);
			}

			logger.info(prep.toString());
			return prep.executeUpdate();
		} catch (Exception e) {
			e.printStackTrace();
			throw new DaoException("执行增删改失败!", e);
		} finally {
			close();
		}
	}

	public void close() {

		DbHelper.close(conn, prep, rs);
	}

}
